#include "ensemble.h"

Ensemble * creer_Ens()
{
  Ensemble *ens = (Ensemble *)malloc (sizeof (Ensemble));
  if(ens)
    init_Ens(ens);
  else
    {
      fprintf(stderr, "Fonction creer_Ens : Malloc, erreur : %s", strerror(errno));
      exit(EXIT_FAILURE);
    }
  return ens;
}

void init_Ens(Ensemble * ensemble)
{
  ensemble->courant = NULL;
  ensemble->debut = NULL;
  ensemble->fin = NULL;
  ensemble->taille = 0;
}

void libere_Ens(Ensemble * ensemble, void (detruire)())
{
  prems_Ens(ensemble);
  if(ensemble->courant)
    {
      while(ensemble->courant->suivant != NULL)
	{
	  suppSuiv_Ens(ensemble, detruire);
	}
      suppPrems_Ens(ensemble, detruire);
    }
}

void detruire_Ens(Ensemble ** ensemble, void (detruire)())
{
  if(ensemble && (*ensemble))
    {
      libere_Ens((*ensemble), detruire);
    }
  free(*ensemble);
  (*ensemble) = NULL;
}

void copier_Ens(Ensemble **dest, Ensemble *src, void * (*creer)(), void (*detruire)(), void (*copier)())
{
  /* Destruction de dest */
  Item *itemCourant;
  int i, j;
  if((*dest) == NULL)
    {
      (*dest) = creer_Ens();
    }
  if((*dest)->debut)
    {
      itemCourant = (*dest)->debut;
      do
	{
	  detruire(&(itemCourant->data));
	  itemCourant = itemCourant->suivant;
	}while(itemCourant->suivant != NULL);
      libere_Ens((*dest), detruire);
    }
  if(src)
    {
      /* Insertion de chaque element dans dest */  
      j = getTaille_Ens(src);
      prems_Ens(src);
      for(i = 0; i < j; i++)
	{
	  void *data = NULL;
	  data = creer();
	  copier(&data, getData_Ens(src));
	  insert_Ens((*dest), data, creer);
	  suivant_Ens(src);
	  detruire(&data);
	}
    }
}

void insert_Ens(Ensemble *ensemble, void *data, void *(*creer)(void *))
{
  Item *itemCourant;
  Item *itemNouveau;
  if(ensemble != NULL)
    {
      itemCourant = ensemble->courant;
      itemNouveau = (Item *) malloc (sizeof(Item));
      
      if(itemNouveau)
	{
	  itemNouveau->data = NULL;
	  if(creer != NULL)
	    itemNouveau->data = creer(data);
	  else
	    itemNouveau->data = data;

	  if(itemCourant == NULL)
	    {
	      if(ensemble->debut == NULL)
		{
		  ensemble->debut = itemNouveau;
		  ensemble->fin = itemNouveau;
		  itemNouveau->suivant = NULL;
		}
	      else
		{
		  itemNouveau->suivant = ensemble->debut;
		  ensemble->debut = itemNouveau;
		  ensemble->courant = ensemble->debut;
		}
	    }
	  else
	    {
	      itemNouveau->suivant = itemCourant->suivant;
	      itemCourant->suivant = itemNouveau;
	      if(itemNouveau->suivant == NULL)
		ensemble->fin = itemNouveau;
	    }
	  ensemble->courant = itemNouveau;
	  ensemble->taille++;
	}
      else
	{
	  fprintf (stderr, "Insert_Ens : Malloc, erreur : %s\n", strerror(errno));
	  exit (EXIT_FAILURE);
	}
    }
}

void suppSuiv_Ens(Ensemble * ensemble, void (*detruire)())
{
  Item *itemCourant;
  Item *itemSupp;
  if(ensemble && ensemble->courant)
    {
      itemCourant = ensemble->courant;
      itemSupp = itemCourant->suivant;
      if(itemSupp != NULL)
	{
	  itemCourant->suivant = itemSupp->suivant;
	  if(itemSupp == ensemble->fin)
	    ensemble->fin = itemCourant;
	  if(detruire != NULL)
	    detruire(&(itemSupp->data));
	  free(itemSupp);	  
	}
      itemSupp = NULL;
      ensemble->taille --;
    }
}

void suppCourant_Ens(Ensemble * ensemble, void (*detruire)())
{
  Item *itemSupp;

  if(ensemble && ensemble->taille > 0)
    {
      if(ensemble->courant == ensemble->debut)
	{
	  suppPrems_Ens(ensemble, detruire);
	}
      else
	{
	  itemSupp = ensemble->courant;
	  ensemble->courant = ensemble->debut;
	  while(ensemble->courant->suivant != itemSupp)
	    {
	      ensemble->courant = ensemble->courant->suivant;
	      if(ensemble->courant == NULL)
		break;
	    }
	  suppSuiv_Ens(ensemble, detruire);
	}
      ensemble->taille --;
    }
}

void suppPrems_Ens(Ensemble * ensemble, void (*detruire)())
{
  if(ensemble && ensemble->taille > 0)
    {
      ensemble->courant = ensemble->debut->suivant;
      if(ensemble->debut == ensemble->fin)
	ensemble->fin = NULL;
      if(detruire != NULL)
	detruire(&(ensemble->debut->data));
      free(ensemble->debut);
      ensemble->debut = ensemble->courant;
      ensemble->taille--;
    }
}

void suivant_Ens(Ensemble * ensemble)
{
  if(ensemble && ensemble->courant)
    {
      ensemble->courant = ensemble->courant->suivant;
    }
}

void * getData_Ens(Ensemble * ensemble) 
{
  return ((ensemble && ensemble->courant) ? ensemble->courant->data : NULL);
}

void prems_Ens(Ensemble * ensemble)
{
  if(ensemble)
    ensemble->courant = ensemble->debut;
}

void dernier_Ens(Ensemble * ensemble)
{
  if(ensemble)
    ensemble->courant = ensemble->fin;
}

size_t getTaille_Ens(Ensemble * ensemble)
{
  if(ensemble)
    return ensemble->taille;
  return 0;
}

int estDernierElement_Ens(const Ensemble *ens)
{
  if(ens == NULL || ens->courant == NULL)
    return 1;
  if(ens->courant->suivant == NULL)
    return 1;
  return 0;
}

int possedeElement_Ens(Ensemble *ptr, void *e, int (*compare)(void *, void *))
{
  Item *dep;
  dep = ptr->debut;
  while(dep)
    {
      if(compare(e, dep->data) == 1)
	{
	  ptr->courant = dep;
	  return 1;
	}
      dep = dep->suivant;
    }
  return 0;
}
